#ifndef DW_GRAFFITI_PROGRAM_H
#	define DW_GRAFFITI_PROGRAM_H

#include "enums.h"
#include "shader.h"
#include "declaration.h"

namespace dw {
	namespace graffiti {

struct ProgramAttributeDeclaration
{
	const char* name;
	AttributeDeclaration declaration;
	bool normalize;
};

struct ProgramUniformDeclaration
{
	uniform::type::types type;
	dw::uint32 count;
	dw::uint32 location;
};

class Program
{
public : // !@name Types definitions
	//! @{
	//! @}

public : //! @name Construction & Destruction
	//! @{
	Program();
	~Program();
	//! @}

public : //! @name Commands
	//! @{
	template< GLenum shaderType >
	void attach(const Shader< shaderType >& shader);
	void link(const ProgramAttributeDeclaration* attributesDecl, dw::uint32 attributesDeclCount);
	void activate();
	void deactivate();
	void enableAttributes();
	void disableAttributes();
	//! @}
	
public : //! @name State
	//! @{
	dw::uint32 getAttributesHashcode() const ;
	bool getAttributeLocation(const AttributeDeclaration& attribute, dw::uint32& location, bool& normalize) const ;
	bool hasAttribute(const AttributeDeclaration& attribute) const ;
	bool isValid() const ;
	bool isLinked() const ;

	const ProgramUniformDeclaration* getUniformDeclaration(const std::string& name) const ;
	//! @}

private : //! @name Types definitions
	//! @{
	struct InternalAttributeDeclaration
	{
		std::string name;
		AttributeDeclaration declaration;
		dw::uint32 count;
		bool normalize;
		dw::uint32 location;
	};
	//! @}

private : //! @name Internal helpers
	//! @{
	void getAttributesLocation(const ProgramAttributeDeclaration* attributesDecl, dw::uint32 attributesDeclCount);
	void getUniformsLocation();
	//! @}

private : //! @name Copy protection
	//! @{
	Program(const Program& ref);
	//! @}

private : //! @name Types definitions
	//! @{
	typedef std::map< dw::uint32, InternalAttributeDeclaration > AttributesMap;
	typedef std::map< std::string, ProgramUniformDeclaration > UniformsMap;
	//! @}

private : //! @name Data
	//! @{
	GLuint m_id;

	AttributesMap m_attributes;
	UniformsMap m_uniforms;

	dw::uint32 m_attributesHashcode;
	//! @}
};

	} // namespace graffiti
} // namespace dw

#include "program.inl"

#endif // !DW_GRAFFITI_PROGRAM_H
